package com.cnb.servlet.v2.context;

import com.cnb.servlet.util.StrUtil;
import com.cnb.servlet.v1.annotation.Autowrite;
import com.cnb.servlet.v1.annotation.Controller;
import com.cnb.servlet.v1.annotation.Service;
import com.cnb.servlet.v2.beans.BeanWrapper;
import com.cnb.servlet.v2.beans.config.BeanDefinition;
import com.cnb.servlet.v2.beans.factory.BeanFactory;
import com.cnb.servlet.v2.beans.factory.support.BeanDefinitionReader;
import com.cnb.servlet.v2.beans.factory.support.DefaultListableBeanFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

public class ApplicationContext implements BeanFactory {

    private DefaultListableBeanFactory registry = new DefaultListableBeanFactory();

    //将创建过的保存在这个set里面 做为标记
    private Set<String> singletonsCurrentlyCreation = new HashSet<>();

    //一级缓存 key:beanName v:查出来的对象
    private Map<String,Object> singletonObjects = new HashMap<>();

    //二级缓存
    private Map<String,Object> earlySingletonObjects = new HashMap<>();

    //三级缓存
    private Map<String,BeanWrapper> factoryBeanInstanceCache = new HashMap<>();

    private Map<String,Object> factoryBeanObjectCache = new HashMap<>();

    private BeanDefinitionReader reader = null;

    public ApplicationContext(String...location) {
        //加载配置文件
        reader = new BeanDefinitionReader(location);

        try {
            //解析配置文件,将所有的配置信息封装成BeanDefinition对象
            List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //将所有的配置信息缓存起来
            registry.doRegistBeanDefinition(beanDefinitions);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //加载非延迟加载的Bean
       doLoadInstance();
    }

    public void doLoadInstance() {
        this.registry.beanDefinitionMap.forEach((k,v) ->{
            if(v.isLazy()){return;}
            getBean(k);
        });
    }

    @Override
    public Object getBean(String beanName) {
        //获取出Bean的定义信息
        Optional<BeanDefinition> beanDefinitionOptional = Optional.of(this.registry.beanDefinitionMap.get(beanName));
        BeanDefinition beanDefinition = beanDefinitionOptional.orElse(new BeanDefinition());

        Object singleton = getSingleton(beanName,beanDefinition);

        if(singleton != null){
            return singleton;
        }

        /**
         * 如果singleton取出来的数据是Null,同时该beanName在singletonsCurrentlyCreation存在,说明此时有循环依赖
         */
        if(!this.singletonsCurrentlyCreation.contains(beanName)){
            singletonsCurrentlyCreation.add(beanName);
        }

        Object instance = instantiateBean(beanName, beanDefinition);

        BeanWrapper wrapper = new BeanWrapper(instance);

        populateBean(beanName,beanDefinition,wrapper);

        this.factoryBeanInstanceCache.put(beanName,wrapper);
        return wrapper.getWrapperedInstance();
    }

    private Object getSingleton(String beanName, BeanDefinition beanDefinition) {

        return null;
    }

    /**
     * 实例化Bean
     * @param beanName Bean的名称
     * @param bd Bean的定义信息
     */
    private Object instantiateBean(String beanName, BeanDefinition bd) {
        if(StrUtil.isBlank(bd.getFactoryClassName())){return null;}
        Object instance = null;
        try {
            Class<?>  aClass = Class.forName(bd.getFactoryClassName());
            instance = aClass.getDeclaredConstructor().newInstance();

            //AOP的入口

            this.factoryBeanObjectCache.put(beanName,instance);
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return instance;
    }

    private void populateBean(String beanName, BeanDefinition bd, BeanWrapper wrapper) {
        Object instance = wrapper.getWrapperedInstance();
        Class<?> clazz = wrapper.getWrappedClass();

        if(!(clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Service.class))){
            return;
        }

        for (Field field : clazz.getDeclaredFields()) {
            //判断该字段有没有加Autowrite注解,如果没有就遍历下一个字段
            if(!field.isAnnotationPresent(Autowrite.class)){
                continue;
            }
            Autowrite autowriteAnnotation = field.getAnnotation(Autowrite.class);
            String autowriteBeanName = "";
            //如果这里的field是一个接口,那么这里beanName将是一个该接口的全限定名
            if(field.getType().isInterface()){
                autowriteBeanName = field.getType().getName();
            }else{
                if(!StrUtil.isBlank(autowriteAnnotation.value())){
                    autowriteBeanName = autowriteAnnotation.value().trim();
                }else{
                    //这里都会将该字段的变量名首字母转成小写
                    autowriteBeanName = StrUtil.toLowerCaseFirst(field.getName());
                }
            }
            field.setAccessible(true);
            try {
                if(this.factoryBeanInstanceCache.get(autowriteBeanName) == null){
                    continue;
                }
                field.set(instance,this.factoryBeanInstanceCache.get(autowriteBeanName).getWrapperedInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public <T> T getBean(Class<T> requiredType) {
        return null;
    }

    public int getBeanDefinitionCount(){
        return this.registry.beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames(){
        return this.registry.beanDefinitionMap.keySet().toArray(new String[0]);
    }
}
